<template>
  <div class="triangle-basic">
    <h1>渐变三角形</h1>
    <p>通过在顶点着色器中添加颜色属性，并利用WebGL的颜色插值功能，我们可以实现三角形的渐变效果。这是理解WebGL中顶点属性和片元着色器插值机制的重要示例。</p>

    <el-card class="demo-section">
      <template #header>
        <div class="card-header">
          <h3>渐变三角形的绘制</h3>
        </div>
      </template>
      <div class="demo-content">
        <canvas ref="demoCanvas" width="400" height="300"></canvas>
        <div class="control-panel">
          <el-form :model="triangleForm" label-width="100px">
            <el-form-item label="顶点1颜色">
              <el-color-picker v-model="triangleForm.color1" @change="updateTriangle" />
            </el-form-item>
            <el-form-item label="顶点2颜色">
              <el-color-picker v-model="triangleForm.color2" @change="updateTriangle" />
            </el-form-item>
            <el-form-item label="顶点3颜色">
              <el-color-picker v-model="triangleForm.color3" @change="updateTriangle" />
            </el-form-item>
            <el-form-item label="绘制模式">
              <el-select v-model="triangleForm.mode" @change="updateTriangle">
                <el-option label="填充" value="TRIANGLES" />
                <el-option label="线框" value="LINE_LOOP" />
              </el-select>
            </el-form-item>
          </el-form>
          <div class="position-info">当前模式: {{ triangleForm.mode }}</div>
        </div>
      </div>
    </el-card>

    <el-card class="code-section">
      <template #header>
        <div class="card-header">
          <h3>示例代码</h3>
        </div>
      </template>
      <div class="code-content">
        <pre><code>
// 顶点着色器
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
  gl_Position = a_Position;
  v_Color = a_Color;
}

// 片元着色器
precision mediump float;
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}

// JavaScript代码
const canvas = document.getElementById('webgl');
const gl = canvas.getContext('webgl');

// 创建着色器程序...

// 设置顶点位置和颜色
const vertices = new Float32Array([
   0.0,  0.5,  1.0, 0.0, 0.0, 1.0,  // 顶点1：位置和颜色(红色)
  -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,  // 顶点2：位置和颜色(绿色)
   0.5, -0.5,  0.0, 0.0, 1.0, 1.0   // 顶点3：位置和颜色(蓝色)
]);

// 设置顶点属性...

// 绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, 3);
        </code></pre>
      </div>
    </el-card>

    <el-card class="info-section">
      <template #header>
        <div class="card-header">
          <h3>渐变三角形说明</h3>
        </div>
      </template>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="顶点数据">
          每个顶点包含位置(x,y)和颜色(r,g,b,a)信息
        </el-descriptions-item>
        <el-descriptions-item label="颜色插值">
          WebGL会自动对顶点之间的颜色进行插值，形成平滑的渐变效果
        </el-descriptions-item>
        <el-descriptions-item label="着色器变量">
          使用varying变量在顶点着色器和片元着色器之间传递颜色数据
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { WebGLUtils, colorUtils } from '@/utils/webgl'

const demoCanvas = ref<HTMLCanvasElement | null>(null)
const gl = ref<WebGLRenderingContext | null>(null)
const shaderProgram = ref<WebGLProgram | null>(null)
const webglUtils = ref<WebGLUtils | null>(null)

const triangleForm = reactive({
  color1: '#FF0000',
  color2: '#00FF00',
  color3: '#0000FF',
  mode: 'TRIANGLES'
})

// 初始化WebGL
const initWebGL = () => {
  if (!demoCanvas.value) return

  // 获取WebGL上下文
  gl.value = demoCanvas.value.getContext('webgl')
  if (!gl.value) {
    console.error('Failed to get WebGL context')
    return
  }

  // 创建WebGL工具实例
  webglUtils.value = new WebGLUtils(gl.value)

  // 顶点着色器源码
  const vertexShaderSource = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    varying vec4 v_Color;
    void main() {
      gl_Position = a_Position;
      v_Color = a_Color;
    }
  `

  // 片元着色器源码
  const fragmentShaderSource = `
    precision mediump float;
    varying vec4 v_Color;
    void main() {
      gl_FragColor = v_Color;
    }
  `

  // 创建着色器
  const vertexShader = webglUtils.value.createShader(gl.value.VERTEX_SHADER, vertexShaderSource)
  const fragmentShader = webglUtils.value.createShader(gl.value.FRAGMENT_SHADER, fragmentShaderSource)
  if (!vertexShader || !fragmentShader) return

  // 创建程序并链接着色器
  shaderProgram.value = webglUtils.value.createProgram(vertexShader, fragmentShader)
  if (!shaderProgram.value) return

  gl.value.useProgram(shaderProgram.value)

  // 更新三角形
  updateTriangle()
}

// 更新三角形属性并重绘
const updateTriangle = () => {
  if (!gl.value || !shaderProgram.value || !webglUtils.value) return

  // 转换颜色
  const color1 = colorUtils.hexToRgb(triangleForm.color1)
  const color2 = colorUtils.hexToRgb(triangleForm.color2)
  const color3 = colorUtils.hexToRgb(triangleForm.color3)

  // 设置顶点数据（位置和颜色）
  const vertices = new Float32Array([
     0.0,  0.5,  color1.r, color1.g, color1.b, 1.0,
    -0.5, -0.5,  color2.r, color2.g, color2.b, 1.0,
     0.5, -0.5,  color3.r, color3.g, color3.b, 1.0
  ])

  // 创建并绑定缓冲区
  const vertexBuffer = webglUtils.value.createBuffer(vertices)
  if (!vertexBuffer) return

  // 设置顶点位置属性
  const a_Position = gl.value.getAttribLocation(shaderProgram.value, 'a_Position')
  // stride = (2个位置分量 + 4个颜色分量) * Float32Array.BYTES_PER_ELEMENT = 24字节
  // offset = 0（位置数据从头开始）
  gl.value.vertexAttribPointer(a_Position, 2, gl.value.FLOAT, false, 6 * Float32Array.BYTES_PER_ELEMENT, 0)
  gl.value.enableVertexAttribArray(a_Position)

  // 设置顶点颜色属性
  const a_Color = gl.value.getAttribLocation(shaderProgram.value, 'a_Color')
  // stride = 同上 = 24字节
  // offset = 2个位置分量 * Float32Array.BYTES_PER_ELEMENT = 8字节（跳过位置数据）
  gl.value.vertexAttribPointer(a_Color, 4, gl.value.FLOAT, false, 6 * Float32Array.BYTES_PER_ELEMENT, 2 * Float32Array.BYTES_PER_ELEMENT)
  gl.value.enableVertexAttribArray(a_Color)

  // 设置清除颜色并清除
  gl.value.clearColor(0.0, 0.0, 0.0, 1.0)
  gl.value.clear(gl.value.COLOR_BUFFER_BIT)

  // 绘制三角形
  const drawMode = triangleForm.mode === 'TRIANGLES' ? gl.value.TRIANGLES : gl.value.LINE_LOOP
  gl.value.drawArrays(drawMode, 0, 3)
}

// 组件挂载时初始化WebGL
onMounted(() => {
  initWebGL()
})
</script>

<style lang="scss" scoped>
.triangle-basic {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;

  h1 {
    color: #303133;
    margin-bottom: 20px;
  }

  p {
    margin-bottom: 30px;
  }

  .demo-section,
  .code-section,
  .info-section {
    margin: 30px 0;

    .card-header {
      display: flex;
      align-items: center;

      h3 {
        margin: 0;
        color: #409EFF;
      }
    }
  }

  .demo-section {
    .demo-content {
      display: flex;
      gap: 20px;

      canvas {
        border: 1px solid #dcdfe6;
        background-color: #000;
      }

      .control-panel {
        flex: 1;
        padding: 20px;
        background-color: #f8f9fa;
        border-radius: 4px;

        .position-info {
          margin-top: 20px;
          text-align: center;
          color: #606266;
          font-family: monospace;
        }
      }
    }
  }

  .code-section,
  .info-section {
    .code-content {
      background-color: #f8f9fa;
      padding: 15px;
      border-radius: 4px;

      code {
        font-family: monospace;
        color: #409EFF;
      }

      pre {
        margin: 0;
        white-space: pre-wrap;
      }
    }
  }
}
</style>
